#include "SPSegment.h"

#include "SPage.h"

SPSegment::SPSegment(Segment& s) : segment(s)
{
}


/**
 * Searches through the segment's pages
 * looking for a page with enough space to store r. If no space is found, grows the
 * segment. Returns the TID identifying the location where r was stored.
 */
TID SPSegment::insert(const Record& r)
{
    for (unsigned i = 0; i < this->segment.getPageCount(); i++)
    {
        BufferFrame& page = this->segment.getPage(i, false);
        SPage spage = SPage::fromExisting(page, *this);

        signed slot = spage.insert(r);
        if (slot != -1)
        {
            TID* tid = new TID;
            tid->pageId = i;
            tid->slotId = slot;
            this->segment.unfixPage(page, true);
            return *tid;
        }

        this->segment.unfixPage(page, false);
    }

    // Segment muss vergrößert werden
    this->segment.requestPages(1,1);
    unsigned pageId = this->segment.getPageCount()-1;
    BufferFrame& page = this->segment.getPage(pageId, false);
    SPage spage = SPage::fromNew(page, *this);

    // Record in der neuen Page abspeichern
    signed slot = spage.insert(r);
    if (slot != -1)
    {
        TID* tid = new TID;
        tid->pageId = pageId;
        tid->slotId = slot;
        this->segment.unfixPage(page, true);
        return *tid;
    }
    this->segment.unfixPage(page, false);

    cout << "Something bad happened: Record cannot be saved in empty page." << endl;
    exit(1);
}


/**
 * Deletes the record pointed to by tid and
 * updates the page header accordingly.
 */
bool SPSegment::deleteRecord(TID tid)
{
    BufferFrame& page = this->segment.getPage(tid.pageId, false);
    SPage spage = SPage::fromExisting(page, *this);
    bool result = spage.clear(tid.slotId);
    this->segment.unfixPage(page, true);
    return result;
}


/**
 * Returns a pointer to the read-only record
 * associated with TID tid.
 */
Record SPSegment::lookup(TID tid)
{
    BufferFrame& page = this->segment.getPage(tid.pageId, false);
    SPage spage = SPage::fromExisting(page, *this);
    Record result = spage.get(tid.slotId);
    this->segment.unfixPage(page, false);
    return result;
}


bool SPSegment::update(TID tid, const Record& r)
{
    return this->update(tid, r, true);
}

bool SPSegment::update(TID tid, const Record& r, bool allowOutsourcing)
{
    BufferFrame& page = this->segment.getPage(tid.pageId, true);
    SPage spage = SPage::fromExisting(page, *this);

    bool result = spage.update(tid.slotId, r, allowOutsourcing);
    this->segment.unfixPage(page, true);

    return result;
}



//SPage& getPage(unsigned index, bool exclusive) {
//    BufferFrame& page = this->segment.getPage(index, exclusive);
//    SPage spage = SPage::fromExisting(page, *this);
//    return spage;
//}


//void unfixPage(SPage& page, bool dirty) {
//    this->segment.unfixPage(page.getPage(), dirty);
//}

SPSegment::~SPSegment()
{
}
